package com.cheche.dn.error;

import com.cheche.dn.Result;
import com.cheche.dn.utils.JsonUtil;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.Map;

/**
 * Http Error Handler
 * Created by cheshun on 15/5/8.
 */
@Controller
public class CustomErrorController implements ErrorController {

    private static final Logger LOG = LoggerFactory.getLogger(CustomErrorController.class);
    private static final String ERROR_PATH = "/error";

    /**
     * Display an error page, as defined in web.xml <code>custom-error</code> element.
     */
    @RequestMapping(ERROR_PATH)
    @ResponseBody
    public Object generalError(HttpServletRequest request, HttpServletResponse response) {
        // retrieve some useful information from the request
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
        // String servletName = (String) request.getAttribute("javax.servlet.error.servlet_name");
        // String errorMessage = (String) request.getAttribute("javax.servlet.error.message");
        String errorMessage = getExceptionMessage(throwable, statusCode);
        String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri");
        if (requestUri == null) {
            requestUri = "Unknown";
        }

        String message = MessageFormat.format("Http code {0} returned for {1} with message {2}.",
                statusCode, requestUri, errorMessage
        );

        Map<String, Object> header = Maps.newHashMap();
        Enumeration<String> keys = request.getHeaderNames();
        while (keys.hasMoreElements()) {
            String key = keys.nextElement();
            header.put(key, request.getHeader(key));
        }

        String exceptionMessage = String.format("ExceptionInfo: \nStatusCode->( %d )\nUrl->( %s )\nMethod->( %s )\nParameter->( %s )\nHeader->( %s )",
                statusCode, requestUri, request.getMethod(), JsonUtil.toJson(request.getParameterMap()), JsonUtil.toJson(header));

        LOG.error(exceptionMessage, throwable);

        return Result.error(ErrorCode.ERROR, message);
    }

    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
    private String getExceptionMessage(Throwable throwable, Integer statusCode) {
        if (throwable != null) {
            return Throwables.getRootCause(throwable).getMessage();
        }
        HttpStatus httpStatus = HttpStatus.valueOf(statusCode);
        return httpStatus.getReasonPhrase();
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }
}
